#pragma  GCC optimize(3)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>

using namespace std;

template<const int _n,const int BLOCK_SIZE>
struct Block_List
{
	struct Block
	{
		char	val[BLOCK_SIZE+3]; int	size; Block*	next;
		Block() { clear(); } void clear() { size=0,memset(val,0,sizeof(val)); }
	}*begin,*end,U[3100];

	int	ALL,tot;
	char	ch[2200000];
	Block*	Trash[3100];

	Block* ALLOC() { if(tot) return Trash[tot--]; return U+(ALL++); }
	void	RECYCLE(Block* t) { memset(t,0,sizeof(Block)); Trash[++tot]=t; }

	Block_List() { ALL=0; begin=ALLOC(); end=ALLOC(); begin->next=end; }

	pair<Block*,int>	Get_Block(const int pos)
	{
		int	Sum=0;Block* t;
		for(Block* i=begin;i!=end;i=i->next)
		{
			if(Sum+i->size>=pos)return make_pair(i,pos-Sum);
			Sum+=i->size;t=i;
		}
		return make_pair(t,t->size);
	}

	Block*	split(Block* t,const int pos)
	{
		Block* nd=ALLOC();
		for(int i=pos;i<t->size;++i)
			nd->val[i-pos]=t->val[i];
		nd->size=t->size-pos;
		t->size=pos;
		nd->next=t->next;
		t->next=nd;
		return t;
	}

	void	Union(Block* t1,Block* t2)
	{
		if(t1->size+t2->size<BLOCK_SIZE>>1 || !t1->size)
		{
			for(int i=0;i<t2->size;++i)push_back(t1,t2->val[i]);
			t1->next=t2->next;
			RECYCLE(t2);
		}
	}

	void	ReUnion()
	{
		Block* t;
		for(Block* i=begin;i && i->next && i->next->next;)
			t=i->next->next,
				Union(i,i->next),
				i=t;
		return ;
	}

	void	push_back(Block* t,const int d)
	{
		t->val[t->size++]=d;
	}

	void	set(const int pos,const char* str)
	{
		pair<Block*,int> t=Get_Block(pos);
		Block *s=split(t.first,t.second),*temp=s->next;
		Block*	nd=ALLOC();
		s->next=nd;
		s=nd;int n=strlen(str);
		for(int i=0;i<n;++i)
		{
			if(i%BLOCK_SIZE==0 && i)
			{
				nd=ALLOC();
				s->next=nd;
				s=nd;
			}
			s->val[s->size++]=str[i];
		}
		s->next=temp;
		ReUnion();
	}

	char*	get(const int pos,const int n)
	{
		static int temp=0;
		temp++;
		pair<Block*,int> t=Get_Block(pos);
		for(int i=0;i<n;++i)
		{
			if(t.second==t.first->size)t.first=t.first->next,t.second=0;
			while(!t.first->size)
				Union(t.first,t.first->next);
			ch[i]=t.first->val[t.second];
			t.second++;
		}
		ch[n]=0;
		return ch;
	}

	void	erase(const int pos,const int n)
	{
		pair<Block*,int> x=Get_Block(pos);
		Block* l=split(x.first,x.second),*t,*s;
		pair<Block*,int> y=Get_Block(pos+n);
		Block* r=split(y.first,y.second),*temp=r->next;
		s=r->next;
		for(Block* i=l->next;i!=s;)
			t=i,i=i->next,RECYCLE(t);
		l->next=temp;
		Union(l,l->next);
	}

	char&	operator[](const int pos)
	{
		pair<Block*,int> t=Get_Block(pos);
		if(t.second==t.first->size)t.first=t.first->next,t.second=0;
		while(!t.first->size) Union(t.first,t.first->next);
		return t.first->val[t.second];
	}
};

int	n;
char	s[2200000];
Block_List<2200000,1483>L;

int main()
{
	int	pos=0,T,x;
	char	op[15];

	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",op);
		if(op[0]=='M')scanf("%d",&x),pos=x;
		else if(op[0]=='I')
		{
			scanf("%d",&n);int cnt=0;
			while(n)
			{
				scanf("%c",&s[cnt]);
				if(s[cnt]!='\n' && s[cnt]!='\r')cnt++,n--;
			}
			s[cnt]=0;
			L.set(pos,s);
		}
		else if(op[0]=='D') scanf("%d",&n),L.erase(pos,n);
		else if(op[0]=='G') scanf("%d",&n),printf("%s\n",L.get(pos,n));
		else if(op[0]=='P') pos--;
		else if(op[0]=='N') pos++;
	}
	return 0;
}
